package org.timemachine.query;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

//TODO TimeMachineException class'larini yaz
//TODO kodu trace et patlayabilecek yerlerde Exception firlat
//TODO degisik hsql'ler ile kodu test et...

public class TimeMachineQuery {

	private static List<String> generatedStatementList = null;
	private static List<String> generatedJoinStatementList = null;
	private static List<String> generatedJoinQueryList = null;

	public static Query createTimeMachineQuery(String sql, EntityManager em,
			Date versionDate) throws Exception {

		String querySql = generateQuery(sql).getSql();
		Query query = em.createQuery(querySql)
				.setParameter("date", versionDate);

		return query;
	}

	public static QueryEntity generateQuery(String sql)
			throws Exception {

		QueryEntity queryEntity = new QueryEntity();

		TimeMachineQueryParser queryParser = new TimeMachineQueryParser();
		queryEntity = parseQueryElements(queryParser, sql, queryEntity);
		String resultQuery = prepareResultQuery(queryParser, sql,
				generatedStatementList, generatedJoinStatementList);
		queryEntity.setSql(resultQuery);

		for (QueryEntity joinQueryEntity : queryEntity.getJoinList()) {
			joinQueryEntity = parseQueryElements(queryParser,
					joinQueryEntity.getSql(), joinQueryEntity);
			String resultJoinQuery = prepareResultQuery(queryParser,
					joinQueryEntity.getSql(), generatedStatementList,
					generatedJoinStatementList);
			joinQueryEntity.setSql(resultJoinQuery);
		}

		return queryEntity;
	}

	public static List<String> generateJoinQueryList(String sql)
			throws Exception {

		TimeMachineQueryParser queryParser = new TimeMachineQueryParser();
		// parseQueryElements(queryParser, sql);
		List<String> joinQueryList = prepareJoinQuery(queryParser, sql,
				generatedJoinStatementList);

		return joinQueryList;
	}

	public static QueryEntity parseQueryElements(
			TimeMachineQueryParser queryParser, String baseSql,
			QueryEntity queryEntity) {

		Map<String, String> objectJoinPair = null;

		Map<String, String> tableAliasPairs = queryParser
				.getTableNamesAndAlias(baseSql);
		queryEntity.setEntityName(tableAliasPairs.keySet().toArray()[0]
				.toString());
		queryEntity.setEntityAlias(tableAliasPairs.get(queryEntity
				.getEntityName()));

		Map<String, String> tableAliasPairWithChange = queryParser
				.prepareTableNames(tableAliasPairs);

		generatedStatementList = queryParser
				.prepareFromStatement(tableAliasPairWithChange);

		String joinStatement = queryParser.getJoinStatement(baseSql);

		if (joinStatement != null && !"".equals(joinStatement)) {
			queryEntity = queryParser.parseJoinStatement(queryEntity,
					joinStatement);
		}

		// Map<String, String> joinTableAliasPairWithChange =
		// queryParser.prepareTableNames(objectJoinPair);

		// generatedJoinStatementList = queryParser.prepareFromStatementForJoin(
		// joinTableAliasPairWithChange,queryParser.getAlias(baseSql),queryParser.getJoinStatementType(baseSql));

		generatedJoinStatementList = queryParser.prepareFromStatementForJoin(
				objectJoinPair, queryParser.getAlias(baseSql),
				queryParser.getJoinStatementType(baseSql));

		queryEntity = queryParser.prepareNewQueryStatementForJoin(queryEntity,
				queryParser.getJoinStatementType(baseSql));

		return queryEntity;

	}

	public static String prepareResultQuery(TimeMachineQueryParser queryParser,
			String baseSql, List<String> generatedStatementList,
			List<String> generatedJoinStatementList) throws Exception {

		if (generatedStatementList != null && generatedStatementList.size() > 1) {

			StringBuffer resBuffer = new StringBuffer();

			resBuffer.append(queryParser.getSelectFromStatement(baseSql));
			resBuffer.append(generatedStatementList.get(0));

			// TODO delete?
			// if (generatedJoinStatementList != null
			// && generatedJoinStatementList.size() > 1) {
			// resBuffer.append(generatedJoinStatementList.get(0));
			// }
			// TODO delete?

			resBuffer.append(" where ");
			resBuffer.append(generatedStatementList.get(1));

			// TODO delete?
			// if (generatedJoinStatementList != null
			// && generatedJoinStatementList.size() > 1) {
			// resBuffer.append(generatedJoinStatementList.get(1));
			// }
			// TODO delete?

			if (!"".equals(queryParser.getWhereStatment(baseSql))) {
				resBuffer.append(" and ");
				resBuffer.append(queryParser.getWhereStatment(baseSql));
			} else {
				resBuffer.append(" ");
				resBuffer.append(baseSql.substring(
						(baseSql.indexOf(queryParser
								.discardFromClauseCommands(baseSql)))
								+ queryParser
										.discardFromClauseCommands(baseSql)
										.length(), baseSql.length()));
			}

			return resBuffer.toString();
		} else {
			throw new Exception();
		}

	}

	public static List<String> prepareJoinQuery(
			TimeMachineQueryParser queryParser, String baseSql,
			List<String> generatedJoinStatementList) throws Exception {

		if (generatedJoinStatementList != null
				&& generatedJoinStatementList.size() > 1) {

			StringBuffer resBuffer = new StringBuffer();
			resBuffer.append(generatedJoinStatementList.get(0));

			resBuffer.append(" where ");
			resBuffer.append(generatedJoinStatementList.get(1));

			if (!"".equals(queryParser.getWhereStatment(baseSql))) {
				resBuffer.append(" and ");
				resBuffer.append(queryParser.getWhereStatment(baseSql));
			} else {
				resBuffer.append(" ");
				resBuffer.append(baseSql.substring(
						(baseSql.indexOf(queryParser
								.discardFromClauseCommands(baseSql)))
								+ queryParser
										.discardFromClauseCommands(baseSql)
										.length(), baseSql.length()));
			}

			List<String> joinList = new ArrayList<String>();
			joinList.add(resBuffer.toString());
			return joinList;
		} else {
			throw new Exception();
		}

	}

}
